import { createContext, useContext, useState } from "react"

// 1. 创建一个Context
const ThemeContext = createContext<{
  theme: string
  toggleTheme: () => void
}>({
  theme: "light",
  toggleTheme: () => {},
})

// 2. 创建一个简单的多层级组件树
const ThemedButton = () => {
  // 4. 使用Context
  const { theme, toggleTheme } = useContext(ThemeContext)

  return (
    <button
      onClick={toggleTheme}
      style={{
        backgroundColor: theme === "dark" ? "#333" : "#fff",
        color: theme === "dark" ? "#fff" : "#333",
        padding: "10px 15px",
        border: `1px solid ${theme === "dark" ? "#555" : "#ddd"}`,
      }}
    >
      当前主题: {theme} (点击切换)
    </button>
  )
}

const Toolbar = () => {
  return (
    <div className="toolbar">
      <ThemedButton />
    </div>
  )
}

// 5. 多个Context的例子
const UserContext = createContext<string>("未登录")

const UserDisplay = () => {
  const { theme } = useContext(ThemeContext)
  const user = useContext(UserContext)

  return (
    <div
      style={{
        padding: "10px",
        backgroundColor: theme === "dark" ? "#444" : "#f0f0f0",
        color: theme === "dark" ? "#fff" : "#333",
        borderRadius: "4px",
        marginTop: "10px",
      }}
    >
      当前用户: <strong>{user}</strong>
    </div>
  )
}

// 主组件
const UseContextDemo = () => {
  // 3. 提供Context值
  const [theme, setTheme] = useState<string>("light")
  const [user, setUser] = useState<string>("游客")

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"))
  }

  const toggleUser = () => {
    setUser((prevUser) => (prevUser === "游客" ? "张三" : "游客"))
  }

  return (
    <div className="demo-section">
      <h2>useContext Hook 面试题讲解</h2>

      <div className="card">
        <h3>1. 什么是 useContext?</h3>
        <p>
          useContext 是 React 的一个 Hook，用于获取由 React.createContext
          创建的上下文对象的当前值。
          它允许组件在不通过层层传递的情况下，获取祖先组件传递的数据。
        </p>

        <div className="code-example">
          <code>
            // 创建上下文 const MyContext = createContext(defaultValue); //
            在组件中使用上下文 const value = useContext(MyContext);
          </code>
        </div>
      </div>

      <div className="card">
        <h3>2. useContext 解决了什么问题?</h3>
        <p>
          useContext 主要解决了 prop drilling (属性钻取)
          的问题。在复杂的组件树中，如果顶层组件需要向深层次的子组件传递数据，
          传统方式需要通过每一层组件的 props
          逐层传递，使代码变得复杂且难以维护。
        </p>
        <p>
          使用 Context
          API，可以在顶层组件定义数据，然后在任何子组件中直接获取这些数据，而不需要中间组件的参与。
        </p>
      </div>

      <div className="card">
        <h3>3. useContext 如何使用?</h3>
        <p>使用 useContext 的步骤:</p>
        <ol>
          <li>使用 createContext 创建一个上下文</li>
          <li>使用 Context.Provider 包装组件树并提供值</li>
          <li>在需要的子组件中使用 useContext 获取值</li>
        </ol>

        <div className="code-example">
          <code>
            // 1. 创建上下文 const ThemeContext = createContext('light'); // 2.
            提供上下文值 function App() {"{"}
            return ({'<ThemeContext.Provider value="dark">'}
            {"<ThemedButton />"}
            {"</ThemeContext.Provider>"}
            );
            {"}"}
            // 3. 消费上下文值 function ThemedButton() {"{"}
            const theme = useContext(ThemeContext); return{" "}
            {"<button style={{ background: theme }}>按钮</button>"};{"}"}
          </code>
        </div>
      </div>

      <div className="card">
        <h3>4. 实际示例：主题切换</h3>
        <p>
          这个例子展示了如何使用 Context API
          实现主题切换功能，避免通过多层组件传递主题值：
        </p>

        <div
          className="example-output"
          style={{
            backgroundColor: theme === "dark" ? "#333" : "#f5f5f5",
            padding: "20px",
          }}
        >
          {/* 使用ThemeContext.Provider提供值 */}
          <ThemeContext.Provider value={{ theme, toggleTheme }}>
            <Toolbar />
          </ThemeContext.Provider>
        </div>
      </div>

      <div className="card">
        <h3>5. 常见面试问题: 多个 Context 如何组合?</h3>
        <p>
          React 允许使用多个 Context，只需将 Provider 嵌套即可。每个 Context
          可以独立更新和使用：
        </p>

        <div
          className="example-output"
          style={{
            backgroundColor: theme === "dark" ? "#333" : "#f5f5f5",
            padding: "20px",
          }}
        >
          {/* 嵌套多个Context.Provider */}
          <ThemeContext.Provider value={{ theme, toggleTheme }}>
            <UserContext.Provider value={user}>
              <Toolbar />
              <UserDisplay />
              <button
                onClick={toggleUser}
                style={{
                  marginTop: "10px",
                  backgroundColor: theme === "dark" ? "#555" : "#eee",
                }}
              >
                切换用户
              </button>
            </UserContext.Provider>
          </ThemeContext.Provider>
        </div>

        <div className="code-example">
          <code>
            {"<ThemeContext.Provider value={{ theme, toggleTheme }}>"}
            {"<UserContext.Provider value={user}>"}
            {"<ChildComponents />"}
            {"</UserContext.Provider>"}
            {"</ThemeContext.Provider>"}
          </code>
        </div>
      </div>

      <div className="card">
        <h3>6. 常见面试问题: Context 性能问题</h3>
        <p>
          当 Context 提供的值发生变化时，使用该 Context
          的所有组件都会重新渲染，这可能导致性能问题。减轻这些问题的策略包括:
        </p>
        <ul>
          <li>将状态分割成多个 Context，避免不必要的渲染</li>
          <li>使用 React.memo 优化消费 Context 的组件</li>
          <li>使用 Context 的值控制渲染，而不是整个组件树</li>
          <li>考虑使用其他状态管理方案 (例如 Redux) 处理复杂的全局状态</li>
        </ul>

        <div className="warning">
          <p>
            <strong>性能提示:</strong> Context 主要用于低频更新的数据
            (如主题、用户信息、语言)， 不适合用于高频变化的状态
            (如鼠标位置、表单输入等)。
          </p>
        </div>
      </div>

      <div className="card">
        <h3>7. 常见面试问题: Context 的默认值何时使用</h3>
        <p>
          当创建 Context 时提供的默认值，只有在组件不在任何对应的 Provider
          内时才会使用。 这对于测试组件或在非必需 Provider 的情况下很有用。
        </p>
        <div className="code-example">
          <code>
            // 默认值仅在没有匹配的Provider时使用 const MyContext =
            createContext(defaultValue); // 未被Provider包裹，将使用defaultValue
            function ComponentA() {"{"}
            const value = useContext(MyContext); // 得到defaultValue // ...
            {"}"}
            // 被Provider包裹，将使用providedValue function ComponentB() {"{"}
            return ({"<MyContext.Provider value={providedValue}>"}
            {"<Child />"} {/* Child将获得providedValue */}
            {"</MyContext.Provider>"}
            );
            {"}"}
          </code>
        </div>
      </div>

      <div className="card">
        <h3>8. useContext 面试核心要点</h3>
        <ul>
          <li>useContext 用于消费由 createContext 创建的上下文</li>
          <li>它解决了组件树中的 prop drilling 问题，允许数据在组件树中共享</li>
          <li>当 Context 值变化时，所有使用该 Context 的组件都会重新渲染</li>
          <li>适合共享全局或半全局的数据，如主题、用户信息、语言等</li>
          <li>多个 Context 可以组合使用，但嵌套过多可能导致代码复杂</li>
          <li>
            不是状态管理库的替代品，对于非常复杂的状态逻辑，可能需要考虑使用
            Redux 等
          </li>
        </ul>
      </div>
    </div>
  )
}

export default UseContextDemo
